package com.kanas.webak.rbac.service;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import javax.inject.Singleton;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;


import com.kanas.framework.business.BusinessException;
import com.kanas.webak.admin.domain.AppUser;
import com.kanas.webak.admin.repository.UserRepository;
import com.kanas.webak.organization.domain.Organization;
import com.kanas.webak.organization.repository.OrganizationRepository;
import com.kanas.webak.rbac.domain.AppPermission;
import com.kanas.webak.rbac.domain.AppRole;
import com.kanas.webak.rbac.domain.AppUserRole;
import com.kanas.webak.rbac.repository.PermissionRepository;
import com.kanas.webak.rbac.repository.RoleRepository;
import com.kanas.webak.rbac.repository.UserRoleRepository;

@Service("kanas.rbac0.service.sysroleservice")
@Singleton
public class AppRoleServiceImpl implements AppRoleService {

	@Autowired
	private RoleRepository roleRepository;

	@Autowired
	private UserRepository userRepository;
	
	@Autowired
	private UserRoleRepository userRoleRepository;
	
	@Autowired
	private PermissionRepository permissionRepository;
	
	@Autowired
	private OrganizationRepository orgRepository;
	
	public OrganizationRepository getOrgRepository() {
		return orgRepository;
	}

	public void setOrgRepository(OrganizationRepository orgRepository) {
		this.orgRepository = orgRepository;
	}

	public UserRepository getUserRepository() {
		return userRepository;
	}

	public void setUserRepository(UserRepository userRepository) {
		this.userRepository = userRepository;
	}

	public RoleRepository getRoleRepository() {
		return roleRepository;
	}

	public void setRoleRepository(RoleRepository roleRepository) {
		this.roleRepository = roleRepository;
	}

	public PermissionRepository getPermissionRepository() {
		return permissionRepository;
	}

	public void setPermissionRepository(PermissionRepository permissionRepository) {
		this.permissionRepository = permissionRepository;
	}
	
	public UserRoleRepository getUserRoleRepository() {
		return userRoleRepository;
	}

	public void setUserRoleRepository(UserRoleRepository userRoleRepository) {
		this.userRoleRepository = userRoleRepository;
	}

	@Override
	@Transactional
	public List<AppRole> findAll() {
		return this.roleRepository.findAll();
	}
	
	@Override
	@Transactional
	public List<AppRole> findAllExceptAdmin() {
		return this.roleRepository.findByAdminFlagOrderByExportFlagDescSortNumberAsc(false);
	}
	
	@Override
	@Transactional
	public AppRole findOne(String roleId) {
		return this.roleRepository.findOne(roleId);
	}
	
	@Override
	@Transactional
	public String update(String roleId,AppRole role) {
		AppRole r = roleRepository.findOne(roleId);
		r.setLabel(role.getLabel());
		r.setDescription(role.getDescription());
		r.setEnableFlag(role.getEnableFlag());
		r.setExportFlag(role.getExportFlag());
		this.roleRepository.save(r);
		return roleId;
	}
	
	@Override
	@Transactional
	public String removeFromUser(String userRoleId,String userId){
		AppUserRole r = userRoleRepository.findOne(userRoleId);
		userRoleRepository.delete(r);
		return userId;
	}
	
	@Override
	@Transactional
	public AppRole addNew(AppRole role) throws Exception{
		AppRole ar = roleRepository.findOne(role.getId());
		if(ar != null) throw BusinessException.DATA_DUPLICATION;
		role.setAdminFlag(false);
		roleRepository.save(role);
		return role;
	}
	
	@Override
	@Transactional
	public String delete(String rid) throws Exception {
		AppRole ar = roleRepository.findOne(rid);
		if(ar == null) throw BusinessException.DATA_NOT_FOUND;
		ar.setExtensionRoles(null);
		ar.setInclusionRoles(null);
		ar.setMutex(null);
		ar.setPermissions(null);
		ar.setUserRoles(null);
		ar.setUsers(null);
		this.roleRepository.save(ar);
		this.roleRepository.delete(ar);
		return rid;
	}
	
	@Override
	@Transactional
	public List<AppPermission> listFunction(String rid) {
		AppRole r=this.roleRepository.findOne(rid);
		List<AppPermission> f=this.permissionRepository.findByRole(r);
		return f;
	}
	
	@Override
	@Transactional
	public void savePermission(String rid,String fids){
		String[] ids = fids.split(",");
		AppRole role = roleRepository.findOne(rid);
		List<AppPermission> functionChecked=permissionRepository.findByRole(role);
		for(AppPermission af:functionChecked){
			this.permissionRepository.delete(af);
		}
		Integer idsLength=ids.length;
		AppPermission f = null;
		for(int i=0;i<idsLength;i++){
			f=new AppPermission();
			f.setPermissionId(ids[i]);
			f.setRole(role);
			permissionRepository.save(f);
		}
	}
	
	@Override
	@Transactional 
	public Set<AppRole> findByUserId(String userId){
		List<AppRole> roles=this.roleRepository.findByUsersId(userId);
		Set<AppRole> rs=new HashSet<AppRole>();
		for(AppRole r:roles){
			rs.add(r);
		}
		return rs;
	}

	@Override
	@Transactional
	public List<AppRole> findByEnableFlag(boolean enableFlag) {
		List<AppRole> roles = roleRepository.findByEnableFlag(enableFlag);
		return roles;
	}

	@Override
	@Transactional
	public List<AppRole> findByExportFlagAndEnableFlag(boolean exportFlag,boolean enableFlag) {
		List<AppRole> roles = roleRepository.findByExportFlagAndEnableFlag(exportFlag, enableFlag);
		return roles==null?new ArrayList<AppRole>():roles;
	}
	
	@Override
	@Transactional
	public List<AppRole> inclusionRole(String id) {
		AppRole ar = roleRepository.findOne(id);
		List<AppRole> ars = new ArrayList<AppRole>();
		if(ar!=null && ar.getInclusionRoles()!=null) {
			ars = new ArrayList<AppRole>(ar.getInclusionRoles());
		}
		return ars;
	}

	@Override
	@Transactional
	public String operateInclusionRole(String rid, String id, boolean flag) {
		AppRole ar = roleRepository.findOne(rid);
		AppRole in = roleRepository.findOne(id);
		if(flag) {
			ar.getInclusionRoles().remove(in);
		}else {
			ar.getInclusionRoles().add(in);
		}
		roleRepository.save(ar);
		return id;
	}
	
	@Override
	@Transactional
	public List<AppPermission> findPermissions(String rid) throws Exception {
		List<AppPermission> aps = new ArrayList<AppPermission>();
		List<String> pids = new ArrayList<String>();
		AppRole ar = roleRepository.findOne(rid);
		if(ar == null) throw BusinessException.DATA_NOT_FOUND;
		for(AppPermission ap:ar.getPermissions()) {
			if(!pids.contains(ap.getPermissionId())) {
				pids.add(ap.getPermissionId());
				ap.setChecked(true);
				aps.add(ap);
			}
		}
		for(AppRole r:ar.getInclusionRoles()) {
			for(AppPermission ap:r.getPermissions()) {
				if(!pids.contains(ap.getPermissionId())) {
					pids.add(ap.getPermissionId());
					ap.setChecked(true);
					ap.setRoleLabel(r.getLabel());
					aps.add(ap);
				}
			}
		}
		return aps;
	}
	
	@Override
	@Transactional
	public List<AppUserRole> findUserRoles(String id) throws Exception {
		List<AppUserRole> aus = new ArrayList<AppUserRole>();
		AppRole ar = roleRepository.findOne(id);
		if(ar == null) throw BusinessException.DATA_NOT_FOUND;
		aus = new ArrayList<AppUserRole>(ar.getUserRoles());
		for(AppUserRole au:aus) {
			au.setOrgLabel(au.getOrganization()==null?"":au.getOrganization().getLabel());
			au.setRoleLabel(au.getRole().getLabel());
			au.setUsername(au.getUser().getUsername());
		}
		return aus;
	}
	
	@Override
	@Transactional
	public String newPermission(String rid, String pid) throws Exception {
		AppRole ar = roleRepository.findOne(rid);
		if(ar == null) throw BusinessException.DATA_NOT_FOUND;
		AppPermission ap = permissionRepository.findByRoleAndPermissionId(ar, pid);
		if(ap != null) throw BusinessException.DATA_DUPLICATION;
		AppPermission arp = new AppPermission();
		arp.setPermissionId(pid);
		arp.setRole(ar);
		permissionRepository.save(arp);
		return rid;
	}

	@Override
	@Transactional
	public String removePermission(String pid) {
		permissionRepository.delete(pid);
		return pid;
	}
	
	@Override
	@Transactional
	public String newUserRole(String rid, String oid, String uid) throws Exception {
		AppRole ar = roleRepository.findOne(rid);
		if(ar == null) throw BusinessException.DATA_NOT_FOUND;
		AppUser au = userRepository.findOne(uid);
		if(au == null) throw BusinessException.DATA_NOT_FOUND;
		Organization org = orgRepository.findOne(oid);
		AppUserRole ur = userRoleRepository.findByRoleAndUserAndOrganization(ar, au, org);
		if(ur != null) throw BusinessException.DATA_DUPLICATION;
		ur = new AppUserRole();
		if(org!=null)ur.setOrganization(org);
		ur.setRole(ar);
		ur.setUser(au);
		userRoleRepository.save(ur);
		return rid;
	}

	@Override
	@Transactional
	public String removeUser(String uid) {
		userRoleRepository.delete(uid);
		return uid;
	}

	@Override
	@Transactional
	public List<AppRole> findRoles(String type) {
		List<AppRole> ars = null;
		if(type!=null && type.equals("export")) {
			ars = this.findByExportFlagAndEnableFlag(true, true);
		}else if(type!=null && type.equals("inclusion")) {
			ars = this.findByExportFlagAndEnableFlag(false, true);
		}else if(type!=null && type.equals("disable")){
			ars = this.findByEnableFlag(false);
		}
		return ars==null?new ArrayList<AppRole>():ars;
	}
	
}